﻿using System;
using System.Collections.Generic;
using System.Linq;
using StockModel;
using Utils.Extensions;
using Utils.Wpf;

namespace Plugins.UserControls
{
	public class DateSelectorVM : ViewModelValidatedBase
	{
		#region Attributes

		private DateTime? _firstStartDate;
		private DateTime? _firstEndDate;
		private DateTime? _lastStartDate;
		private DateTime? _lastEndDate;

		private readonly RawStockDataSource _rawStockDataSource;

		#endregion

		#region Properties

		public DateSelectorData Data { get; private set; }

		public bool UseAllDays
		{
			get
			{
				return this.Data.UseAllDays;
			}
			set
			{
				if (this.Data.UseAllDays != value)
				{
					this.Data.UseAllDays = value;
					base.OnPropertyChanged("UseAllDays");
					base.OnPropertyChanged("StartDate"); // To validate again
					base.OnPropertyChanged("EndDate");
				}
			}
		}

		public DateTime? StartDate
		{
			get
			{
				return this.Data.StartDate;
			}
			set
			{
				if (this.Data.StartDate != value)
				{
					this.Data.StartDate = value;
					base.OnPropertyChanged("StartDate");
					base.OnPropertyChanged("FirstEndDate");
				}
			}
		}

		public DateTime? EndDate
		{
			get
			{
				return this.Data.EndDate;
			}
			set
			{
				if (this.Data.EndDate != value)
				{
					this.Data.EndDate = value;
					base.OnPropertyChanged("EndDate");
					base.OnPropertyChanged("LastStartDate");
				}
			}
		}

		public DateTime? FirstStartDate
		{
			get
			{
				return _firstStartDate;
			}
			set
			{
				if (_firstStartDate != value)
				{
					_firstStartDate = value;
					base.OnPropertyChanged("FirstStartDate");
				}
			}
		}

		public DateTime? FirstEndDate
		{
			get
			{
				return this.Data.StartDate ?? _firstEndDate;
			}
			set
			{
				if (_firstEndDate != value)
				{
					_firstEndDate = value;
					base.OnPropertyChanged("FirstEndDate");
				}
			}
		}

		public DateTime? LastStartDate
		{
			get
			{
				return this.Data.EndDate ?? _lastStartDate;
			}
			set
			{
				if (_lastStartDate != value)
				{
					_lastStartDate = value;
					base.OnPropertyChanged("LastStartDate");
				}
			}
		}

		public DateTime? LastEndDate
		{
			get
			{
				return _lastEndDate;
			}
			set
			{
				if (_lastEndDate != value)
				{
					_lastEndDate = value;
					base.OnPropertyChanged("LastEndDate");
				}
			}
		}

		#endregion

		#region Public Methods

		public DateSelectorVM(RawStockDataSource rawStockDataSource)
		{
			_rawStockDataSource = rawStockDataSource;

			this.Data = new DateSelectorData();
			this.Data.PropertyChanged += Data_PropertyChanged; // Local object
		}

		public void LoadAvailableDays(string stockName)
		{
			// ReSharper disable PossibleMultipleEnumeration
			IEnumerable<DateTime> days = _rawStockDataSource.GetAvailableDays(stockName);

			this.FirstStartDate = days.Min();
			this.FirstEndDate = days.Max();
			this.LastStartDate = days.Max();
			this.LastEndDate = this.LastStartDate;
			// ReSharper restore PossibleMultipleEnumeration
		}

		public void ValidateSelectedDays(string stockName)
		{
			// ReSharper disable PossibleMultipleEnumeration
			IEnumerable<DateTime> days = _rawStockDataSource.GetAvailableDays(stockName);

			if (this.UseAllDays) // Do not validate, just set all the days
			{
				this.StartDate = null;
				this.EndDate = null;
			}
			else
			{
				this.StartDate = this.StartDate == null ? days.Min() : this.StartDate.Value.IsBetween(days.Min(), days.Max()) ? this.StartDate : days.Min();
				this.EndDate = this.EndDate == null ? days.Max() : this.EndDate.Value.IsBetween(days.Min(), days.Max()) ? this.EndDate : days.Max();
			}

			this.FirstStartDate = days.Min();
			this.FirstEndDate = days.Max();
			this.LastStartDate = days.Max();
			this.LastEndDate = this.LastStartDate;
			// ReSharper restore PossibleMultipleEnumeration
		}

		protected override string ValidateField(string fieldName)
		{
			string result = null;

			if (fieldName == "StartDate")
			{
				if (!this.UseAllDays && this.StartDate == null)
				{
					base.ValidatedErrors[fieldName] = true;
					result = "The start date cannot be null";
				}
			}
			else if (fieldName == "EndDate")
			{
				if (!this.UseAllDays && this.EndDate == null)
				{
					base.ValidatedErrors[fieldName] = true;
					result = "The end date cannot be null";
				}
			}

			return result;
		}

		#endregion

		#region Event Handlers

		private void Data_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
		{
			base.OnPropertyChanged(e.PropertyName);
		}

		#endregion
	}
}
